﻿using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using NUnit.Framework;
using Assume = DiffLib.QA.Assume;

namespace DiffLib.Tests.QA
{
    [TestFixture]
    public class ReferenceTests : QualityTestsBase
    {
        public IEnumerable<MethodInfo> AllMethodsReturningReferenceTypes()
        {
            return from method in AllMethods()
                   where method.ReturnType != typeof(void)
                   where !method.ReturnType.IsValueType
                   select method;
        }

        [Test]
        [TestCaseSource("AllMethodsReturningReferenceTypes")]
        public void Method_ReturningReferenceType_MustBeTaggedWithNotNullAttributeOrCanBeNullAttribute(MethodInfo method)
        {
            if (method.IsDefined(typeof(NotNullAttribute), true))
                return;
            if (method.IsDefined(typeof(CanBeNullAttribute), true))
                return;

            Assume.That(method.DeclaringType != null);
            Assert.Fail("Method " + method.Name + " of type " + method.DeclaringType.FullName + " returns reference type but is not tagged with [NotNull] or [CanBeNull]");
        }

        private IEnumerable<PropertyInfo> AllPropertiesHoldingReferenceTypes()
        {
            return from property in AllProperties()
                   where !property.PropertyType.IsValueType
                   select property;
        }

        [Test]
        [TestCaseSource("AllPropertiesHoldingReferenceTypes")]
        public void Property_HoldingReferenceType_MustBeTaggedWithNotNullAttributeOrCanBeNullAttribute(PropertyInfo property)
        {
            if (property.IsDefined(typeof(NotNullAttribute), true))
                return;
            if (property.IsDefined(typeof(CanBeNullAttribute), true))
                return;

            Assume.That(property.DeclaringType != null);
            Assert.Fail("Property " + property.Name + " of type " + property.DeclaringType.FullName + " returns reference type but is not tagged with [NotNull] or [CanBeNull]");
        }
    }
}
